package net.chrisrichardson.ormunit.hibernate;

import java.util.ArrayList;
import java.util.List;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.dialect.Dialect;
import org.hibernate.tool.hbm2ddl.DatabaseMetadata;

public class HibernateSchemaChecker {

	private final Configuration configuration;
	private SessionFactory sessionFactory;

	public HibernateSchemaChecker(Configuration configuration, SessionFactory sessionFactory) {
		this.configuration = configuration;
		this.sessionFactory = sessionFactory;
	}

	protected Dialect getDatabaseDialect() throws Exception {
	    return (Dialect)Class.forName(
	            configuration.getProperty(
	                    "hibernate.dialect"))
	            .newInstance();
	}

	List getSignificantDifferences(
	        String[] script) {
	    List differences = new ArrayList();
	    for (int i = 0; i < script.length; i++) {
	        String line = script[i];
	        if (line.indexOf("add constraint") == -1)
	            differences.add(line);
	    }
	    return differences;
	}

	String[] generateScript()
	        throws Exception {
	    Session session = sessionFactory.openSession();
	    try {
	        Dialect dialect = getDatabaseDialect();
	        DatabaseMetadata dbm = new DatabaseMetadata(
	                session.connection(), dialect);
	        String[] script = configuration
	                .generateSchemaUpdateScript(
	                        dialect, dbm);
	        return script;
	    } finally {
	        session.close();
	    }
	}

	/**
	 * Verifies that all tables and columns referenced by the object/relational mapping
	 * exist
	 * @param tests TODO
	 * @throws Exception
	 */
	public void assertDatabaseSchema()
	        throws Exception {
	    String[] script = generateScript();
	    List differences = getSignificantDifferences(script);
	    HibernateSchemaTests.assertTrue(differences.toString(), differences
	            .isEmpty());
	}

}
